﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Spi;

namespace NGuice.Inject
{
    /// <summary>
    /// C#泛型没有通配符，使用标记接口解决此问题
    /// </summary>
    public interface IBinding : IElement 
    {
        /// <summary>
        /// 绑定对应的key
        /// </summary>
        Key Key
        {
            get;
        }

        /// <summary>
        /// NGuice中范围化提供者，用于此绑定的填充请求
        /// </summary>
        /// <exception cref="NotSupportException">
        /// 当通过NGuice.Inject.Spi.Elements.GetElements创建的Binding时调用跑出此异常。此方法不支持从注入器中返回Binding
        /// </exception>
        IProvider Provider
        {
            get;
        }

        /// <summary>
        /// 接受一个范围访问者
        /// </summary>
        V AcceptScopingVisitor<V>(IBindingScopingVisitor<V> visitor);
    }

    /// <summary>
    /// 一个key（type类型和可选的元注释）到获取类型的实例策略的一个映射对象。此接口是内省API的接口，并主要被工具使用。
    /// Binding使用以下几个方式创建：
    /// <list type="bullet">
    /// <item>
    /// 在一个模块中显式的通过<code>Bind()</code>方法或<code>BindConstant()</code>方法声明：
    /// <code>
    /// Bind(typeof(Service)).AnnotatedWith(typeof(Red)).To(typeof(ServiceImpl)));
    /// BindConstant().AnnotatedWith(typeof(ServerHost)).To(args[0]);
    /// </code>
    /// </item>
    /// <item>
    /// <description>被注入器以下列类型隐式的绑定：ImplementedBy、ProvidedBy元特性或者通过使用Inject元特性或默认的构造器</description>
    /// </item>
    /// <item>
    /// 通过转换一个边界实例到一个不同类型
    /// </item>
    /// <item>
    /// 对于Provider，通过为提供者类型代理到binding
    /// </item>
    /// </list>
    /// 绑定映射存在于模块和注入器中，但他们的行为时不一样的：
    /// <list type="bullet">
    /// <item>
    /// Module bindings:不完整的，并且不能被用于提供实例。这是因为兼容的scope范围和拦截器可能直到注入器被创建后才被知晓。
    /// 从工具的角度讲，模块绑定类似于注入器的源代码。他们能够被内省或重写，但所有分析都是静态的
    /// </item>
    /// <item>
    /// Injector bindings：完整的并有效的，并且能够用于提供实例。从工具的角度讲，注入器绑定类似于注入器的反射。他们具有完全
    /// 的运行时信息，包括完整的对绑定安全必要的注入图
    /// </item>
    /// </list>
    /// </summary>
    /// <typeparam name="X">边界类型，注入总是兼容此类型</typeparam>
    public interface IBinding<T> : IBinding
    {

        /// <summary>
        /// 绑定对应的key
        /// </summary>
        Key<T> Key
        {
            get;
        }

        /// <summary>
        /// NGuice中范围化提供者，用于此绑定的填充请求
        /// </summary>
        /// <exception cref="NotSupportException">
        /// 当通过NGuice.Inject.Spi.Elements.GetElements创建的Binding时调用跑出此异常。此方法不支持从注入器中返回Binding
        /// </exception>
        IProvider<T> Provider
        {
            get;
        }

        /// <summary>
        /// 接受一个目标访问者。调用访问方法指定此绑定目标
        /// </summary>
        V AcceptTargetVisitor<V>(IBindingTargetVisitor<T, V> visitor);

    }
}
